﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Runtime.Serialization;
using System.Windows;
using DependencyAnalysis;

namespace AnalysisHost
{
    public partial class App
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            try
            {
                if (e.Args.Length > 0)
                {
                    ProcessPipeClient(e.Args[0]);
                }
            }
            finally
            {
                Current.Shutdown();
            }
        }

        public void ProcessPipeClient(string pipeName)
        {

            using (var pipeClient =
                new NamedPipeClientStream(".", pipeName, PipeDirection.InOut))
            {

                pipeClient.Connect();
                var analysisResult = new AnalysisResult();

                try
                {
                    var modules = new List<string>();
                    var reader = new StreamReader(pipeClient);
                    {
                        string temp;
                        WaitForSynchronization(reader, () => false);
                        while ((temp = reader.ReadLine()) != null && temp != Synchronization)
                        {
                            modules.Add(temp);
                        }
                    }
                    Setup setup = StartAnalysis(modules);
                    setup.Model.InstructionCache.Serialize();
                    analysisResult = new AnalysisResult
                    {
                        DependencyModel = setup.Model
                    };
                }
                catch (Exception)
                {
                    // TODO write somewhere
                }

                var writer = new StreamWriter(pipeClient);
                {
                    writer.WriteLine(Synchronization);
                    writer.Flush();
                    SerializeToStream(analysisResult, pipeClient);
                    pipeClient.WaitForPipeDrain();
                }

            }

        }

        private Setup StartAnalysis(IEnumerable<string> modules)
        {
            var setup = Setup.BuildStandardSetup();
            setup.StartAnalysis(modules);
            return setup;
        }

        public static void SerializeToStream(object objectType, Stream stream)
        {
            DataContractSerializer serializer = new DataContractSerializer(typeof(AnalysisResult), null, int.MaxValue, true, true, null);
            serializer.WriteObject(stream, objectType);
        }

        public static object DeserializeFromStream(Stream stream)
        {
            DataContractSerializer serializer = new DataContractSerializer(typeof(AnalysisResult));
            return serializer.ReadObject(stream);
        }

        public static void WaitForSynchronization(StreamReader reader, Func<bool> breakingCondition)
        {
            string temp;
            do
            {
                temp = reader.ReadLine();
                System.Threading.Thread.Sleep(50);
                if (breakingCondition()) return;
            } while (temp == null || !temp.StartsWith(Synchronization));
        }

        public const string Synchronization = ",*SYNCHRONIZATION*,";
    }
}
